package service

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	"github.com/pkg/errors"
	"github.com/redwarn/gotool/httpclient"
	"github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"
)

const (
	releaseUrl  = "http://cmdb.oriente.com"
	releaseUser = "tiger"
	releasePwd  = "Oriente0326Oriente0326Oriente0326Oriente0326"
	tmpFile     = "http://cmdb.oriente.com/down/ci/email.html"
	testUrl     = "http://54.255.237.41:8818"
	testToken   = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjkwNjA0ODIsImlzcyI6InRpZ2VyIn0.va6AR5ecWkVvpBXiYNJ2DXAz30oCcJYIpDzEL7XGvi0"
)

type User struct {
	User     string
	Password string
}

func newUser() *User {
	return &User{
		User:     releaseUser,
		Password: releasePwd,
	}
}
func (u *User) getTeken() (error, string) {
	var token string
	data := map[string]string{
		"username": u.User,
		"password": u.Password,
	}
	res := httpclient.PostParams(releaseUrl+"/user/login", "", data)
	loginInfo := &struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
		Data    struct {
			Token string
		} `json:"data"`
	}{}
	if res.StatusCode == http.StatusOK {
		err := json.Unmarshal(res.Body, loginInfo)
		if err != nil {
			return err, ""
		}
		if loginInfo.Errcode != 0 {
			logrus.Error("user login error", loginInfo.Errmsg)
			return errors.New(loginInfo.Errmsg), ""
		}
		token = loginInfo.Data.Token
	} else {
		return errors.New("http status code not 200"), token
	}
	return nil, token
}

type ReleaseNote struct {
	Country   string   `yaml:"COUNTRY"`
	DEP       []string `yaml:"DEP"`
	DB1       []string `yaml:"DB1"`
	DB2       []string `yaml:"DB2"`
	Increment []string `yaml:"INCREMENT"`
	Comments  []string `yaml:"COMMENTS"`
	Branch    string
	Tag       string `json:"ProjectTag"`
	Author    string
	Project   string `json:"ProjectName"`
	Notice    string
	Online    struct {
		Tag         string
		Contains    bool
		LackCommits []string
	}
}

func NewReleaseNote(filePath string) *ReleaseNote {
	releaseNote := &ReleaseNote{}
	if ok, err := FileExists(filePath); !ok {
		if err == nil {
			filePath = "./release.yml"
		} else {
			panic("没有找到release.yaml or release.yml文件")
		}
	}
	bs, err := ioutil.ReadFile(filePath)
	if os.IsNotExist(err) {
		panic("没有找到release.yaml or release.yml文件")
	}
	if err != nil {
		return releaseNote
	}
	err = yaml.Unmarshal(bs, releaseNote)
	if err != nil {
		logrus.Errorf("parse release.yal error, %v", err.Error())
		panic("release.yml 文件格式不对，请查看https://oriente.atlassian.net/wiki/spaces/COTTSC/pages/881590921/1+release.yaml")
	}
	return releaseNote
}

func (r *ReleaseNote) ToJson() (string, error) {
	jsonData, err := json.Marshal(r)
	if err != nil {
		logrus.Error("releaseNote Marshal json failure ", err)
		return "", err
	}
	return string(jsonData), err
}

func (r *ReleaseNote) SetTag(tag string) {
	r.Tag = tag
}

// GITLAB_USER_EMAIL

func (r *ReleaseNote) SetAuthor(email string) {
	r.Author = email
}

func (r *ReleaseNote) SetName(Project string) {
	r.Project = Project
}

func downFile(url string) (string, error) {
	var f *os.File
	var err error
	fileName := "./email.html"
	if f, err = os.Create(fileName); err != nil {
		return fileName, err
	}
	res, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()
	_, err = io.Copy(f, res.Body)
	if err != nil {
		return "", err
	}
	return fileName, nil
}
func (r *ReleaseNote) Send() (bool, error) {
	fileName, err := downFile(tmpFile)
	user := newUser()
	err, token := user.getTeken()
	if err != nil {
		return false, err
	}

	if err != nil {
		logrus.Error("down template file error", err)
		return false, err
	}
	t, _ := template.ParseFiles(fileName)
	var body bytes.Buffer
	err = t.Execute(&body, r)
	if err != nil {
		logrus.Error("template reader error", err)
		return false, err
	}
	data := map[string]string{
		"subject": fmt.Sprintf("Handover testing- %s : %s : %s", r.Project, r.Tag, strings.Join(r.Increment, "-")),
		"content": string(body.Bytes()),
		"type":    "text/html",
		"to":      r.Author,
		"cc":      "regionalbackendteam@oriente.com",
	}
	emailRes := httpclient.PostParams(releaseUrl+"/api/v1/send/email", token, data)

	result := &struct {
		Errcode int    `json:"errcode"`
		Errmsg  string `json:"errmsg"`
	}{}

	if emailRes.StatusCode == 200 {
		err := json.Unmarshal(emailRes.Body, result)
		if err != nil {
			logrus.Error("call email api error", err)
			return false, err
		}
		if result.Errcode != 0 {
			logrus.Error("send email error", err)
			return false, errors.New(result.Errmsg)
		}
	} else {
		return false, errors.New("call email api http status code" + string(emailRes.StatusCode))
	}

	deployData := &struct {
		ProjectName string       `json:"projectName"`
		ProjectTag  string       `json:"projectTag"`
		Content     *ReleaseNote `json:"content"`
	}{
		r.Project,
		r.Tag,
		r,
	}

	dataJson, _ := json.Marshal(deployData)
	res := httpclient.PostJson(testUrl+"/deploycenter/deploy/auto", testToken, string(dataJson))
	if res.StatusCode != 200 {
		logrus.Error("call deploycenter api error http status: ", res.StatusCode)
		return false, errors.New(string(res.Body))
	}
	return true, nil
}
